package cn.wolfcode.shop.mq;

import cn.wolfcode.shop.common.BusinessException;
import cn.wolfcode.shop.common.Result;
import cn.wolfcode.shop.service.IOrderInfoService;
import cn.wolfcode.shop.service.ISeckillGoodService;
import cn.wolfcode.shop.web.frontend.OrderInfoController;
import cn.wolfcode.shop.web.result.SeckillServerCodeMsg;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Component
public class OrderMQListener {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ISeckillGoodService seckillGoodService;

    @Autowired
    private IOrderInfoService orderInfoService;

    @RabbitListener(queuesToDeclare = {@Queue(MQConstants.ORDER_PEDDING_QUEUE)})
    public void handlerOrderPeddingQueue(@Payload OrderMessage orderMessage, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws IOException {
        HashMap<String, Object> param = new HashMap<>();
        param.put("uuid",orderMessage.getUuid());
        param.put("seckillGoodId",orderMessage.getSeckillGoodId());
        try {
            String orderNo = orderInfoService.seckill(orderMessage.getUserId(), orderMessage.getSeckillGoodId());
            param.put("code", Result.SUCCESS_CODE);
            param.put("orderNo",orderNo);
            rabbitTemplate.convertAndSend(MQConstants.ORDER_RESULT_EXCHANGE,MQConstants.ORDER_RESULT_SUCCESS_KEY,param);
        }catch (Exception e){
            e.printStackTrace(); // 记录日志
            param.put("code", SeckillServerCodeMsg.SECKILL_ERROR.getCode());
            param.put("msg", SeckillServerCodeMsg.SECKILL_ERROR.getMsg());
            rabbitTemplate.convertAndSend(MQConstants.ORDER_RESULT_EXCHANGE,MQConstants.ORDER_RESULT_FAIL_KEY,param);
        }finally {
            channel.basicAck(deliveryTag,false);
        }
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(MQConstants.ORDER_RESULT_FAIL_QUEUE),
            exchange = @Exchange(name = MQConstants.ORDER_RESULT_EXCHANGE, type = "topic"),
            key = MQConstants.ORDER_RESULT_FAIL_KEY
    ))
    public void handlerOrderResultFialQueue(@Payload Map<String,Object> param, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws IOException {
        try {
            Long seckilGoodId = (Long) param.get("seckillGoodId");
            seckillGoodService.syncStock(seckilGoodId);
        }catch (Exception e){
            e.printStackTrace(); // 记录日志
            // 可以往MQ中放消息，监听这个消息，通知后台人员进行手动同步一下
        }finally {
            channel.basicAck(deliveryTag,false);
        }
    }

    @Bean
    public org.springframework.amqp.core.Queue delayQueue(){
        Map<String,Object> arguments = new HashMap<>();
        arguments.put("x-dead-letter-exchange",MQConstants.DELAY_EXCHANGE);
        arguments.put("x-dead-letter-routing-key",MQConstants.ORDER_DELAY_KEY);
        arguments.put("x-message-ttl",1000*60*1);// 设置超时时间
        org.springframework.amqp.core.Queue queue = new org.springframework.amqp.core.Queue(MQConstants.ORDER_RESULT_SUCCESS_DELAY_QUEUE,true,false,false,arguments);
        return queue;
    }
    @Bean
    public Binding binding1a(org.springframework.amqp.core.Queue delayQueue) {
        return BindingBuilder.bind(delayQueue)
                .to(new TopicExchange(MQConstants.ORDER_RESULT_EXCHANGE))
                .with(MQConstants.ORDER_RESULT_SUCCESS_KEY);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(MQConstants.ORDER_TIMEOUT_QUEUE),
            exchange = @Exchange(name = MQConstants.DELAY_EXCHANGE, type = "topic"),
            key = MQConstants.ORDER_DELAY_KEY
    ))
    public void handlerOrderTimeoutQueue(@Payload Map<String,Object> param, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws IOException {
        try {
            String orderNo = (String) param.get("orderNo");
            Long seckillGoodId = (Long) param.get("seckillGoodId");
            orderInfoService.cancelTimeOutOrder(orderNo,seckillGoodId);
        }catch (BusinessException ex){
            ex.printStackTrace(); //记录日志信息
        }catch (Exception e){
            e.printStackTrace(); // 记录日志信息
            // 可以往MQ中放消息，监听这个消息，通知后台人员进行手动同步一下
        }finally {
            channel.basicAck(deliveryTag,false);
        }
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue,
            exchange = @Exchange(name = MQConstants.SECKILL_OVER_SIGN_PUBSUB_EX, type = "fanout")
    ))
    public void handlerCancelLocalSignQueue(@Payload Long seckillGoodId, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws IOException {
        try {
            System.err.println("取消本地标识");
            OrderInfoController.STOCK_OVER_SIGN.put(seckillGoodId,false);
            System.err.println(OrderInfoController.STOCK_OVER_SIGN);
        }catch (Exception e){
            e.printStackTrace(); // 记录日志
            // 可以往MQ中放消息，监听这个消息，通知后台人员进行手动同步一下
        }finally {
            channel.basicAck(deliveryTag,false);
        }
    }

}
